import React, { useState, useRef, useEffect, useMemo } from 'react';
import { Layout, Input, Button, List, Avatar, message, Row, Card, Col, Menu, Space, notification, } from 'antd';
import { CaretDownOutlined, CaretUpOutlined, ChromeOutlined, ConsoleSqlOutlined } from '@ant-design/icons';
import { encrypt, backgroundObj } from '@/utils/utils';
import TextArea from '../TextArea';
import { connect, history } from 'umi'
import dayjs from 'dayjs';
import {
    CopyOutlined,
    ReloadOutlined,
    LikeOutlined,
    DislikeOutlined
} from "@ant-design/icons";
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
import MathJaxRender from '../MathJaxRender';
import PopImgShow from '@/components/PopImgShow';
import remarkMath from "remark-math";
import rehypeKatex from 'rehype-katex';
import 'katex/dist/katex.min.css';
import './index.less';
const { Header, Content, Footer } = Layout;
const handleCopy = (text) => {
    navigator.clipboard.writeText(text)
    notification.success({
        message: '温馨提示',
        description: '复制成功',
    });
};
const MessageActions = ({ onCopy, onRegenerate, onLike, onDislike, isRight, msg }) => {
    const { likeFlag } = msg
    return (
        <div className={`actionBar ${isRight ? 'rightActions' : ''}`}>
            <CopyOutlined onClick={onCopy} title="复制" />
            {likeFlag === '0' || !likeFlag ? <>
                <LikeOutlined onClick={onLike} title="喜欢" />
                <DislikeOutlined onClick={onDislike} title="喜欢" />
            </> : likeFlag === '1' ? <LikeOutlined style={{ color: 'red' }} title="喜欢" /> : <DislikeOutlined style={{ color: 'red' }} title="不喜欢" />}

        </div>
    );
};
function hasMathFormulaAdvanced(str) {

    const delimiterPairs = [
        ["\\$\\$", "\\$\\$"],    // $$...$$
        ["\\$", "\\$"],          // $...$
        ["\\\\\\[", "\\\\\\]"],  // \[...\]
        ["\\\\\\(", "\\\\\\)"],  // \(...\)
        ["\\(", "\\)"],          // (...)
        ["\\[", "\\]"],          // [...]
        ["\\$", "\\$"],          // $...$ (重复项)
        ["\\$\\\\", "\\$"],      // $\...$
        ["\\\\n", "\\\\n"]       // \n...\n
    ];

    // 构建正则表达式模式
    const patterns = delimiterPairs.map(([start, end]) => {
        return new RegExp(`^${start}([\\s\\S]*?)${end}$`);
    });

    // 检查是否匹配任意一个模式
    return patterns.some(pattern => pattern.test(str));

}
function hasMath(str) {
    const mathRegex = /(\$(?:[^$]|\\\$)*\$)|(\\\(|\\\)|\\\[|\\]|\\\{|\\\})|(\\?(?:sum|int|prod|sqrt|frac|lim)|[α-ωΑ-ΩπθΣµ∂∆∇√∞∫≈≠≤≥])|(\b(sin|cos|tan|frac|exp|ln)\b\s*\(?)/i;
    return mathRegex.test(str)
}
export const preprocessLaTeX = (content) => {
    const newContent = content.replace(/\\\\\[/g, '$$$$') // Replace '\\[' with '$$'
        .replace(/\\\\\]/g, '$$$$') // Replace '\\]' with '$$'
        .replace(/\\\\\(/g, '$$$$') // Replace '\\(' with '$$'
        .replace(/\\\\\)/g, '$$$$') // Replace '\\)' with '$$'
        .replace(/\\\[/g, '$$$$') // Replace '\[' with '$$'
        .replace(/\\\]/g, '$$$$') // Replace '\]' with '$$'
        .replace(/\\\(/g, '$$$$') // Replace '\(' with '$$'
        .replace(/\\\)/g, '$$$$'); // Replace '\)' with '$$';
    return newContent;
};
const MarkdownComponents = {
    code({ node, inline, className, children, ...props }) {
        const match = /language-(\w+)/.exec(className || '');
        return !inline && match ? (
            <div style={{ border: '1px solid #333', borderRadius: '4px', margin: '16px 0' }}>
                {/* 头部栏 */}
                <div style={{
                    display: 'flex',
                    justifyContent: 'space-between',
                    alignItems: 'center',
                    padding: '8px 12px',
                    background: '#1e1e1e',
                    borderBottom: '1px solid #333',
                    borderRadius: '4px 4px 0 0'
                }}>
                    {/* 语言标签 */}
                    <span style={{ color: '#888', fontSize: '0.875em' }}>
                        {match[1]}
                    </span>
                    {/* 复制按钮 */}
                    <button
                        onClick={() => {
                            handleCopy(String(children))
                        }}
                        style={{
                            background: 'transparent',
                            border: 'none',
                            color: '#888',
                            cursor: 'pointer',
                            fontSize: '0.875em',
                            display: 'flex',
                            alignItems: 'center',
                            gap: '4px'
                        }}
                    >
                        <>
                            <span>⎘</span>
                            <span>复制</span>
                        </>
                    </button>
                </div>
                <SyntaxHighlighter
                    style={vscDarkPlus}
                    customStyle={{
                        margin: '0px'
                    }}
                    language={match[1]}
                    showLineNumbers
                    PreTag="div"
                    {...props}
                >
                    {String(children).replace(/\n$/, '')}
                </SyntaxHighlighter>
            </div>

        ) : (
            <code className={className} {...props}>
                {children}
            </code>
        );
    },
};
function splitByThinkTag(str) {
    const startTag = '<think>';
    const endTag = '</think>';
    const startIndex = str.indexOf(startTag);

    if (startIndex === -1) {
        return { before: '', after: str };
    }

    const contentStart = startIndex + startTag.length;
    const endIndex = str.indexOf(endTag, contentStart); // 从起始标签后开始查找

    if (endIndex === -1) {
        // 没有闭合标签，提取起始标签后的全部内容
        const before = str.substring(contentStart);
        return { before, after: '' };
    } else {
        // 提取两个标签之间的内容
        const before = str.substring(contentStart, endIndex);
        const after = str.substring(endIndex + endTag.length);
        return { before: preprocessLaTeX(before), after };
    }
}
const MessagesList = ({ messages, messageType, reload, dispatch }) => {
    const handleCopy = (text) => {
        navigator.clipboard.writeText(text)
        notification.success({
            message: '温馨提示',
            description: '复制成功',
        });
    };
    const LeftRender = (props) => {
        const { msg, } = props
        const [showSk, setshowSk] = useState(true)
        const { before, after } = splitByThinkTag(msg.allContent)
        const onLike = () => {
            dispatch({
                type: 'answering/fakeLikeChat',
                payload: {
                    id: msg.id,
                    likeFlag: '1'
                },
                callback: () => {
                    reload(messageType, {
                        ...msg,
                        likeFlag: '1'
                    })
                }
            })

        }
        const onDislike = () => {
            dispatch({
                type: 'answering/fakeLikeChat',
                payload: {
                    id: msg.id,
                    likeFlag: '0'
                },
                callback: () => {
                    reload(messageType, {
                        ...msg,
                        likeFlag: '0'
                    })
                }
            })
        }
        return <div
            key={msg.id}
            className={`messageBubble received`}
        >
            <div onClick={() => setshowSk(!showSk)} className='received_show_sk'>
                <Space>
                    <ChromeOutlined></ChromeOutlined> 已深度思考完成任务 {showSk ? <CaretDownOutlined ></CaretDownOutlined> : <CaretUpOutlined></CaretUpOutlined>}
                </Space>
            </div>
            {showSk && <div className='received_show_skContent'>
                <div className='received_show_skContentLiner'></div>
                <ReactMarkdown
                    components={MarkdownComponents}
                    remarkPlugins={[remarkMath]}
                    rehypePlugins={[rehypeKatex]}
                >
                    {before}
                </ReactMarkdown>

            </div>}
            <ReactMarkdown
                components={MarkdownComponents}
                remarkPlugins={[remarkMath]}
                rehypePlugins={[rehypeKatex]}
            >
                {after}
            </ReactMarkdown>

            {/* <MathJaxRender content={after}></MathJaxRender> */}
            <MessageActions
                isRight={msg.isSent}
                onCopy={() => handleCopy(msg.allContent)}
                onLike={() => onLike()}
                onDislike={() => onDislike()}
                msg={msg}
            />

        </div >
    }
    const RightRender = (props) => {
        const { msg } = props
        const { files = '', content } = msg
        function isImageFile(path) {
            // 提取文件扩展名（不区分大小写）
            const extension = path.split('.').pop().toLowerCase();

            // 常见图片扩展名列表
            const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];

            return imageExtensions.includes(extension);
        }
        const imageList = files.length > 0 ? files.split(',') : []
        return <div style={{ textAlign: 'right' }}>
            <div
                key={msg.id}
                className={`messageBubble sent`}
            >
                <div className=''>
                    <div className={'messageContent_file_list'}>
                        {imageList.map(item => {
                            if (!isImageFile(item)) {
                                return <div onClick={() => { window.open(item) }} className="messageContent_file font_hide">
                                    {item}

                                </div>
                            }
                            return <PopImgShow width={80} url={item}></PopImgShow>
                        })}
                    </div>
                    <div className={'messageContent'}>
                        {content}
                    </div>
                </div>

            </div>
        </div>
    }
    const memo = useMemo(() => {
        return (
            <div className={'chatContainer'}>
                {messages.map((msg, index) => {
                    const { role } = msg
                    if (role === 'user') {
                        return <RightRender key={index} msg={msg}></RightRender>
                    } else {
                        return <LeftRender key={index} msg={msg}></LeftRender>
                    }
                })}
            </div>
        );
    }, [messages])
    return memo
};
const Messages = ({ msg, messageType, reload, dispatch, status, error }) => {
    const [showSk, setshowSk] = useState(true)
    const { before, after } = splitByThinkTag(msg.allContent)
    const onLike = () => {
        dispatch({
            type: 'answering/fakeLikeChat',
            payload: {
                id: msg.id,
                likeFlag: '1'
            },
            callback: () => {
                reload(messageType, {
                    ...msg,
                    likeFlag: '1'
                })
            }
        })

    }
    const onDislike = () => {
        dispatch({
            type: 'answering/fakeLikeChat',
            payload: {
                id: msg.id,
                likeFlag: '2'
            },
            callback: () => {
                reload(messageType, {
                    ...msg,
                    likeFlag: '2'
                })
            }
        })
    }
    const handleCopy = (text) => {
        navigator.clipboard.writeText(text)
        notification.success({
            message: '温馨提示',
            description: '复制成功',
        });
    };
    if (!status && !error && !msg.allContent) {
        return null
    }
    return (
        <div className={'chatContainer'}>
            <div
                key={msg.id}
                className={`messageBubble received`}
            >
                <div onClick={() => setshowSk(!showSk)} className='received_show_sk'>
                    <Space>
                        <ChromeOutlined></ChromeOutlined>{status || error ? '正在思考请耐心等待' : '已深度思考完成任务'}  {showSk ? <CaretDownOutlined ></CaretDownOutlined> : <CaretUpOutlined></CaretUpOutlined>}
                    </Space>
                </div>

                {showSk && <div className='received_show_skContent'>
                    <div className='received_show_skContentLiner'></div>
                    <ReactMarkdown
                        remarkPlugins={[remarkMath]}
                        rehypePlugins={[rehypeKatex]}
                        components={MarkdownComponents}
                    >
                        {before}
                    </ReactMarkdown>
                </div>}
                <div style={{ marginTop: 8 }}>
                    <Button type='link' loading={status && !after}></Button>
                </div>
                <ReactMarkdown
                    remarkPlugins={[remarkMath]}
                    rehypePlugins={[rehypeKatex]}
                    components={MarkdownComponents}
                >
                    {after}
                </ReactMarkdown>

                {!status && <MessageActions
                    isRight={msg.isSent}
                    onCopy={() => handleCopy(msg.allContent)}
                    onLike={() => onLike()}
                    onDislike={() => onDislike()}
                    msg={msg}
                />}

            </div>
        </div>
    );

}
const ChatApp = (props) => {
    const { dispatch, loading, data } = props
    const { title } = data
    const { location = {} } = history
    const { query = {} } = location
    const eventSourceRef = useRef(null); // 替代全局变量
    const {
        id,
        prompt,
        type = 'install',
        chatId: aiId
    } = query
    const [messages, setMessages] = useState([]);
    const [streamData, setStreamData] = useState('');
    const [value, setValue] = useState('')
    const [status, setStatus] = useState(false);
    const [chatId, setChatId] = useState('')
    const [isAtBottom, setIsAtBottom] = useState(true);
    const [imageList, setImageList] = useState([])
    const chatContainerRef = useRef(null);
    const prevScrollTop = useRef(0);
    const [error, setError] = useState(null);
    const dataBuffer = useRef(''); // 数据缓冲区
    const interVal = useRef(null); // 数据缓冲区
    const messagesEndRef = useRef(null);
    const scrollToBottom = () => {
        messagesEndRef.current?.scrollIntoView({});
    };
    const fetchData = () => {
        return dispatch({
            type: 'answering/fetchListTitleChat',
            payload: {
                titleId: id
            },
            callback: (e) => {
                setMessages(e)
            }

        })

    }
    const submit = async () => {
        if (!value || value.replace(/[\r\n ]/g, '').length === 0) {
            return notification.warning({
                message: '温馨提示',
                description: '请输入问题后提交',
            })
        }
        await fetchData()
        setStreamData('')
        await dispatch({
            type: 'answering/fakeAdminChat',
            payload: {
                titleId: id,
                prompt: value,
                fileList: imageList
            },
            callback: (e) => {
                const { chatId } = e
                setMessages((list) => {
                    return [...list, {
                        id: chatId,
                        role: 'user',
                        title: value,
                        content: value,
                        files: imageList.join(',')
                    }]
                })
                setImageList([])
                setValue('')
                setChatId(chatId)
                postAndStream(chatId)

            }
        })


    }
    const closeSoure = () => {
        if (eventSourceRef.current) {
            eventSourceRef.current.close()
            setStatus(false)
            eventSourceRef.current = null
        }
    }
    const setStreamDataInto = () => {
        if (interVal.current) {
            clearInterval(interVal.current)
        }
        interVal.current = setInterval(() => {
            if (dataBuffer.current.length === streamData) {
                return
            }
            setStreamData(dataBuffer.current)
        }, 200)
    }
    async function postAndStream() {
        if (status) {
            return
        }
        closeSoure()
        const payload = encrypt({
            titleId: id,
            resumeFlag: '1',
            token: window.localStorage.getItem('token'),
            device: 'web'
        })
        const str = Object.keys(payload)
            .map((item) => {
                return `${item}=${payload[item]}`;
            })
            .join("&");

        eventSourceRef.current = new EventSource(APIURL + `/gpt/stream?${str}`);
        setStatus(true)
        eventSourceRef.current.onopen = (event) => {
            setError(null)
            setStatus(true)
            setStreamDataInto()

        }
        // 2. 处理消息事件
        eventSourceRef.current.onmessage = (event) => {
            try {
                const parsedData = JSON.parse(event.data);
                const { content, finishReason, aiChatId } = parsedData
                if (finishReason === 'stop') {
                    closeSoure()
                    clearInterval(interVal.current)
                    setStreamData(dataBuffer.current)
                    dataBuffer.current = ''
                    dispatch({
                        type: 'answering/fetchChatByAiChatId',
                        payload: {
                            chatId: aiChatId
                        },
                        callback: (e) => {
                            const { chatId
                            } = e
                            setChatId(chatId)
                        }
                    })
                    return
                }
                dataBuffer.current += content
            } catch (e) {
                console.error('解析数据失败:', e);
            }
        };
        // 3. 处理错误事件
        eventSourceRef.current.onerror = (error) => {
            closeSoure()
            setError(true)
            setStatus(false)
            setTimeout(() => {
                postAndStream('1')
            }, 5000)
        };
    }
    const reloadInitMessage = (list) => {
        const data = list.reduce((item, val) => {
            if (item) {
                return item
            }
            else if (val.chattingFlag === '1') {
                return val
            }
            else {
                return null
            }
        }, null)
        if (data) {
            postAndStream(data.id, data.chattingFlag)
            setChatId(data.id)
        }
    }
    useEffect(() => {
        dispatch({
            type: 'answering/fetchCheckChatFlag',
            payload: {
                titleId: id
            },
            callback: (e) => {
                if (e.chatFlag === '1') {
                    postAndStream('1')
                }
            }
        })
        fetchData()
        return () => {
            closeSoure()
        }
    }, [])
    useEffect(() => {
        const container = chatContainerRef.current;
        const handleScroll = () => {
            if (!container) return;
            // 判断是否到达底部
            const { scrollTop, scrollHeight, clientHeight } = container;
            const isBottom = scrollHeight - scrollTop <= clientHeight + 30;
            setIsAtBottom(isBottom);
            // 判断滚动方向
            prevScrollTop.current = scrollTop;
        };

        container.addEventListener('scroll', handleScroll);

        // 组件卸载时清除监听
        return () => container.removeEventListener('scroll', handleScroll);
    }, [])
    useEffect(() => {
        if (status) {
            scrollToBottom()
        }
    }, [status])
    useEffect(() => {
        if (isAtBottom && chatContainerRef.current) {
            scrollToBottom();
        }
    }, [messages, streamData]);
    const reload = (messageType, data) => {
        if (messageType === 'bottom') {
            setStreamData('')
            setChatId('')
            fetchData()
        }
        else {
            setMessages((e) => {
                return e.map((item) => {
                    const { id } = item
                    if (id == data.id) {
                        return {
                            ...item,
                            ...data
                        }
                    }
                    return item
                })
            })
        }
    }
    return (
        <Layout className="chat-container">
            <Header className="chat-header">
                <div className="header-content">
                    <h2 className="header-title font_hide">{prompt}</h2>
                </div>
            </Header>
            <Content ref={chatContainerRef} className="chat-content">
                <MessagesList dispatch={dispatch} messageType={'list'} reload={reload} messages={messages}></MessagesList>
                <Messages status={status} error={error} messageType={'bottom'} reload={reload} dispatch={dispatch} msg={
                    {
                        role: "assistant",
                        allContent: streamData,
                        title: prompt,
                        id: chatId
                    }
                }></Messages>
                <div ref={messagesEndRef} />
            </Content>

            <Footer className="chat-footer">
                <div style={{ margin: '0 auto' }} className='AnsweringAis_left_btn'>
                    <div onClick={() => {
                        closeSoure()
                        dispatch({
                            type: 'answering/save',
                            payload: {
                                aiChatData: {}
                            },
                        })
                        history.push({
                            pathname: '/answering/ask',

                        })
                    }} className='AnsweringAis_left_btnStyle'>
                        <div className='AnsweringAis_left_btn1'>
                            <div className='AnsweringAis_icon_style'>
                                <ChromeOutlined></ChromeOutlined>
                            </div>

                            开启新对话
                        </div>
                    </div>
                </div>
                <TextArea
                    setImageList={setImageList}
                    imageList={imageList}
                    loading={status}
                    onOk={submit}
                    value={value}
                    onChange={(e) => {
                        setValue(e.target.value)
                    }}>

                </TextArea>
            </Footer>
        </Layout>
    );
};

export default connect(({ loading, answering }) => ({
    list: answering.dateAiChatTitleList,
    data: answering.aiChatData,
    loading: loading.models.answering,
}))(ChatApp);

